package com.jsy.common.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

public class LargeMappedFiles {
    /**
     * 大数据排序合并
     *
     * @param args
     */
    public static void main(String[] args) throws IOException {
//        // 写入文件的路径
        String filePath = "F:\\汇思工作\\工作文档\\屈臣氏hr学习地图\\历史数据迁移\\文件处理";
//        // 切分文件的路径
        String sqlitFilePath = "F:\\汇思工作\\工作文档\\屈臣氏hr学习地图\\历史数据迁移\\文件处理\\40分";
//        //数据的个数
//        int CountNumbers=10000000;
//
//        //子文件的个数
        int CountFile=40;
//
//        //精度
//        int countAccuracy=30*CountFile;
//
//        long startNumber=System.currentTimeMillis();
//        // 写入大数据文件
//        WriteData(filePath,CountNumbers);
//        System.out.println("存储完毕");
//
//        // 将大数据文件切分到另外的十个小文件中
        sqlitFileDate(filePath, sqlitFilePath,CountFile);
//        System.out.println("文件切割完毕！");
//        // 把每个文件的数据进行排序
//        singleFileDataSort(sqlitFilePath,CountFile);
//        System.out.println("每个子文件排序完毕！");
//
//        //精度调整，十个文件数据进行比较整合
//        deathDataFile(filePath,sqlitFilePath,countAccuracy,CountFile);
//        System.out.println("整合完毕");
//        long stopNumber=System.currentTimeMillis();
//        System.out.println("耗时"+(stopNumber-startNumber)/1000+"毫秒");

    }
    // 写入大数据文件
    public static void WriteData(String path,int CountNumbers) throws IOException {
        path = path + "\\12114.txt";
        FileWriter fs = new FileWriter(path);
        BufferedWriter fw=new BufferedWriter(fs);
        for (int i = 0; i < CountNumbers; i++) {
            fw.write(new Random().nextInt(Integer.MAX_VALUE) + "\r\n");
        }
        fw.close();
        fs.close();

    }
    // 将大数据文件切分到另外的十个小文件中，有问题，会切分文件内容
    public static void sqlitFileDate(String filepath, String sqlitPath,
                                     int CountFile) throws IOException {
        FileWriter fs = null;
        BufferedWriter fw=null;
        FileReader fr = new FileReader(filepath + "\\xianshang1.sql");
        BufferedReader br = new BufferedReader(fr); // 读取获取整行数据

        int i = 1;
        LinkedList WriterLists=new LinkedList();    //初始化文件流对象集合
        LinkedList fwLists=new LinkedList();
        for (int j = 1; j <= CountFile; j++) {

            //声明对象
            fs = new FileWriter(sqlitPath + "\\out" + j + ".sql",false);
            fw=new BufferedWriter(fs);


            //将对象装入集合
            WriterLists.add(fs);
            fwLists.add(fw);
        }
        //判断是文件流中是否还有数据返回
        while (br.ready()) {

            int count=1;//初始化第一文件流
            for (Iterator iterator = fwLists.iterator(); iterator.hasNext();) {
                BufferedWriter type = (BufferedWriter) iterator.next();
                if(i==count)//判断轮到第几个文件流写入数据了
                {
                    //写入数据，跳出，进行下一个文件流，下一个数据的写入
                    type.write(br.readLine() + "\r\n");
                    break;
                }
                count++;
            }
            //判断是否到了最后一个文件流了
            if (i >= CountFile) {
                i = 1;
            } else
                i++;
        }
        br.close();
        fr.close();
        for (Iterator iterator = fwLists.iterator(); iterator.hasNext();) {
            BufferedWriter object = (BufferedWriter) iterator.next();
            object.close();
        }
        //遍历关闭所有子文件流
        for (Iterator iterator = WriterLists.iterator(); iterator.hasNext();) {
            FileWriter object = (FileWriter) iterator.next();
            object.close();
        }
    }
    // 把每个文件的数据进行排序
    public static void singleFileDataSort(String path1,int CountFile) throws IOException {
        LinkedList nums = null;
        for (int i = 1; i <= CountFile; i++) {
            nums = new LinkedList();
            String path = path1 + "\\12" + i + ".txt";
            try {
                FileReader fr = new FileReader(path);
                BufferedReader br = new BufferedReader(fr);
                while (br.ready()) {
                    // 将读取的单个数据加入到集合里面
                    nums.add(Integer.parseInt(br.readLine()));
                }
                // 对集合进行排序
                Collections.sort(nums);
                // 将排序好的数据写入源文件
                numberSort(nums, path);
                br.close();
                fr.close();
            } catch (NumberFormatException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    // 对每个文件数据进行排序，再写入源文件
    public static void numberSort(LinkedList list, String path) {
        try {
            FileWriter fs = new FileWriter(path);
            BufferedWriter fw=new BufferedWriter(fs);
            for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                Object object = (Object) iterator.next();
                fw.write(object + "\r\n");
            }
            fw.close();
            fs.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 文件数据最终整合(精度调整)
    public static void deathDataFile(String filepath, String sqlitFilePath1,
                                     int countAccuracy, int CountFile) throws IOException {
        LinkedList nums = new LinkedList();                                       //添加数据，进行排序
        Object temp = null;                                                       // 记录每次排序剩下的最后一个数字
        boolean ispass = false;
        LinkedList ispasses = null;                                               //记录数据文件的状态信息
        FileWriter fs = new FileWriter(filepath + "\\Sort.txt", false);           //创建文件流，以便整合的数据写入
        BufferedWriter bw=new BufferedWriter(fs);
        FileReader fr = null;                                                     //声明读取文件流
        BufferedReader br = null;                                                 //声明BufferedReader
        LinkedList WriterLists = new LinkedList(); // 初始化文件流对象集合
        LinkedList WriterListFile = new LinkedList();
        for (int j = 1; j <= CountFile; j++) {
            // 声明对象，开启所有子文件流访问所有子文件的数据
            fr = new FileReader(sqlitFilePath1 + "\\12" + j + ".txt");

            //开启所有BufferedReader，方便下次的整行的读取
            br = new BufferedReader(fr);

            // 将所有 FileReader对象装入集合
            WriterListFile.add(fr);

            // 将所有 BufferedReader对象装入集合
            WriterLists.add(br);
        }
        for (;;) {
            // 将十个源文件的是否有数据情况存入集合，以方便后面做判断
            ispasses = new LinkedList();

            // 分别读取十个源文件的单个数据
            for (Iterator iterator = WriterLists.iterator(); iterator.hasNext();) {
                BufferedReader object = (BufferedReader) iterator.next();
                Object obj = null;
                while (object.ready()) {
                    //添加所有文件流的每次的数据
                    nums.add(Integer.parseInt(object.readLine().toString()));
                    break;
                }
                if (object.ready() == false)
                    ispasses.add("true");           //将各文件中的数据状态存入集合中
            }

            // 决断是否是第一次进来
            if (nums.size() % countAccuracy == 0 && ispass == false) {
                // 对集合进行排序
                Collections.sort(nums);
                // 接收最大的数据，其它的数据写入总排序文件
                temp = numberSortData(nums, filepath, false, countAccuracy, bw);

                //重新初始化集合
                nums = new LinkedList();
                // 添加上一组比较剩下的数据
                nums.add(temp);
                ispass = true;
                // 记录源文件的数据数量，以便下次的遍历
                continue;
            }
            if (ispass) {
                if (nums.size() % countAccuracy == 1 && nums.size() > 1) {
                    // 对集合进行排序
                    Collections.sort(nums);
                    // 接收最大的数据，其它的数据写入总排序文件
                    temp = numberSortData(nums, filepath, true, countAccuracy,
                            bw);
                    nums = new LinkedList();
                    nums.add(temp);
                    continue;
                }
            }
            // 记录下一组数据的位置
            // 判断是不是十个文件都没有数据
            if (ispasses.size() == CountFile) {
                Collections.sort(nums);
                temp = numberSortData(nums, filepath, true, countAccuracy, bw);
                nums = new LinkedList();
                break;
            }
        }
        bw.close();
        //关闭写入流
        fs.close();

        //关闭所有的BufferedReader
        for (Iterator iterator = WriterLists.iterator(); iterator.hasNext();) {
            BufferedReader object2 = (BufferedReader) iterator.next();
            object2.close();
        }

        //关闭所有的FileReader
        for (Iterator iterator = WriterListFile.iterator(); iterator.hasNext();) {
            FileReader object = (FileReader) iterator.next();
            object.close();
        }
    }
    // 对数据进行排序,写入最终文件中(精度调整)
    public static Object numberSortData(LinkedList list, String filePath,
                                        boolean ispass, int countAccuracy,BufferedWriter fs) {
        Object temp = 0;                                                        //记录最后一个值
        int tempCount = 0;                                                      //记录写入的数据位置
        try {
            for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                Object object = (Object) iterator.next();
                // 判断是否是最后一个数
                if (tempCount == list.size() - 1) {
                    // 判断集合里面不足一百個數了
                    if (list.size() < countAccuracy + 1 && ispass) {
                        temp = null;
                    } else {
                        temp = object;
                        break;
                    }
                }
                // 写入数据源
                fs.write(object + "\r\n");
                // 记录数据的下标
                tempCount++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return temp;
    }
}